
/****************************************************************************
**
** Copyright (C) 2004-2008 VATATA.com . All rights reserved.
**
** This file is the part of the Miniutil Poject of VATATA.com.
** Vatata's miniutil library is lightweight and portable (for linux
** and Windows). The C++ Class Library included Threadpool, Dll danymic loading, 
** General socket application model and tcp server, httpserver/servlet, etc. 
** It is a pratical utility disigned for who don't want learn the Big C++ 
** Developing Platform, such as  Boost or ACE.
**
** This file may be used under the terms of the GNU General Public
** License versions 2.0 or 3.0 as published by the Free Software
** Foundation and appearing in the files LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file.  Alternatively you may (at
** your option) use any later version of the GNU General Public
** License if such license has been publicly approved by VATATA.com.
** (or its successors, if any) and the Miniutil Project Aministrators. 
**
** Please review the following information to ensure GNU General
** Public Licensing requirements will be met:
** http://www.gnu.org/licenses/lgpl.html. If you are unsure which 
** license is appropriate for your use, please review the following 
** information: http://code.google.com/p/miniutil/ or contact 
** http://www.vatata.com.
**
** In addition, as a special exception, VATATA.com, as the sole
** copyright holder for Miniutil Project, grants users of VATATA
** P2P Platform the right to release and package with the related 
** libraries without the source code.
**
** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE. vatata reserves all rights not expressly
** granted herein.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/


/*

DEPRECATED!!! use miniutil::data::shared_ptr instead!

ref_ptr is not thread-safe
and _ref_data not control destructor!
090615

090702 change to thread-safe... low efficience?
*/


#ifndef MINIUTIL_DATA_REF_PTR_H__
#define MINIUTIL_DATA_REF_PTR_H__

#include <stdlib.h>
#include "miniutil/log.h"
#include "miniutil/thread.h"

namespace miniutil
{
	namespace data
	{
		class ref_ptr_error : public std::runtime_error
		{
		public:
			inline ref_ptr_error( const std::string & msg ) : std::runtime_error(msg)
			{
				M_ERROR( "miniutil::data::ref_ptr_error: %s\n", msg.c_str() );
			}
		};

		template<class T>  
		class   ref_ptr  
		{  
		private:  
			class _ref_data  
			{ 
			public:
				mutable int count;
				T* ptr;
				miniutil::mutex mtx;

				_ref_data()
				{
					count = 0;
					ptr = NULL;
				}

				_ref_data(const _ref_data& other)
				{
					count = other.count;
					ptr = other.ptr;
				}
			} * _data;

			void _release()
			{
				if ( _data == NULL )
					return;
				_data->mtx.lock();
				_data->count --;
				if ( _data->count == 0 )
				{
					delete _data->ptr;
					_data->mtx.unlock();
					delete _data;
					_data = NULL;
				}
				else
					_data->mtx.unlock();
			}

			void _add_ref_copy()
			{
				if ( _data == NULL )
					return;
				miniutil::auto_lock lk(&_data->mtx);
				_data->count ++;
			};

			inline void * operator new( size_t s )
			{
				throw ref_ptr_error("can not new for ref_ptr" );
				return NULL;
			}
			inline void * operator new[]( size_t s )
			{
				throw ref_ptr_error("can not new for ref_ptr" );
				return NULL;
			}
			//inline void * operator&( size_t s )
			//{
			//	throw ref_ptr_error("can not new in ref_ptr" );
			//	return NULL;
			//}

		protected:
			friend class buffer;
			friend class miniutil::auto_lock;

			inline explicit ref_ptr( T *p)  
			{
			  if ( p == NULL )
				  throw ref_ptr_error("give NULL pointer to ref_ptr!");

			  _data  = new _ref_data();//( struct _ref_data *) malloc( sizeof( struct _ref_data));
			  _data->ptr = p;
			  _data->count = 1;
			}  

		public:
			static inline ref_ptr force_cast( T * p )
			{
				return ref_ptr(p);
			}

			static inline ref_ptr safenew( )
			{
				T *p = new T;
				return ref_ptr(p);
			}

			template<class PARAM>
			static inline ref_ptr safenew(const PARAM &param )
			{
				T *p = new T(param);
				return ref_ptr(p);
			}

			template<class P1, class P2>
			static inline ref_ptr safenew(const P1 &p1, const P2 &p2 )
			{
				T *p = new T(p1, p2);
				return ref_ptr(p);
			}
			template<class P1, class P2, class P3>
			static inline ref_ptr safenew(const P1 &p1, const P2 &p2, const P3 &p3 )
			{
				T *p = new T(p1, p2, p3);
				return ref_ptr(p);
			}
			
		public:  

			inline ref_ptr() : _data(NULL)
			{}

			inline ref_ptr(const  ref_ptr&   v0)  
			  :   _data(v0._data)  
			{
				//if ( _data == NULL )
				//	return;
				//_data->count ++;
				_add_ref_copy();
			} 

#define DO_NEW true


			template<class PARAM>
			inline explicit ref_ptr( bool new_ptr_param )  
			{
				T * p = new T;
				_data  = new _ref_data();//( struct _ref_data *) malloc( sizeof( struct _ref_data));
				_data->ptr = p;
				_data->count = 1;
			}  

			template<class PARAM>
			inline explicit ref_ptr( bool new_ptr_param, const PARAM & param )  
			{
				T * p  = new T( param );
				_data  = new _ref_data();//( struct _ref_data *) malloc( sizeof( struct _ref_data));
				_data->ptr = p;
				_data->count = 1;
			}  

			template<class P1, class P2>
			inline explicit ref_ptr( bool new_ptr_param, const P1 & p1, const P2 &p2 )  
			{
				T * p = new T( p1, p2 );
				_data  = new _ref_data();//( struct _ref_data *) malloc( sizeof( struct _ref_data));
				_data->ptr = p;
				_data->count = 1;
			}  
			template<class P1, class P2, class P3>
			inline explicit ref_ptr( bool new_ptr_param, const P1 & p1, const P2 &p2 , const P3 &p3 )  
			{
				T * p = new T( p1 , p2, p3 );
				_data  = new _ref_data();//( struct _ref_data *) malloc( sizeof( struct _ref_data));
				_data->ptr = p;
				_data->count = 1;
			}  

			inline ~ref_ptr()  
			{
				_release();
			}  

/*
			inline ref_ptr & operator=(ref_ptr &   v0)  
			{  
				if (_data   !=   v0._data)  
				{
					_release();
					_data   =   v0._data;  
					if ( _data != NULL )
						_data->count++;
				}  
				return   *this;  
			} 
*/

			inline ref_ptr & operator=(const ref_ptr & v0)  
			{  
				if (_data != v0._data)  
				{
					_release();
					_data = v0._data; 
					_add_ref_copy();
				}  
				return   *this;  
			}  
		  
			inline T&   operator*()  
			{  
				if ( _data == NULL || _data->ptr == NULL )
				  throw ref_ptr_error("NULL pointer [ref_ptr]");
			  return   *(T*)(_data->ptr);  
			}  
			inline const   T&   operator*()   const  
			{  
				if ( _data == NULL || _data->ptr == NULL )
				  throw ref_ptr_error("NULL pointer [ref_ptr]");
			  return   *(T*)(_data->ptr);  
			}  

			inline T*   operator->()  
			{  
				if ( _data == NULL || _data->ptr == NULL )
				  throw ref_ptr_error("NULL pointer [ref_ptr]");
			  return   (T*)(_data->ptr);  
			}  
			const   T*   operator->()   const  
			{  
				if ( _data == NULL || _data->ptr == NULL )
				  throw ref_ptr_error("NULL pointer [ref_ptr]");
			  return   (T*)(_data->ptr);  
			}

			inline bool isNull() const
			{
				return ( _data == NULL || _data->ptr == NULL );
			}
		  
			inline int count()
			{
				return _data->count;
			}
			inline T* get() const
			{
				if ( _data == NULL || _data->ptr == NULL )
					return NULL;
				return (T*)( _data->ptr);
			} 

		};


		template<class T, class U> inline bool operator==(miniutil::data::ref_ptr<T> const & a, miniutil::data::ref_ptr<U> const & b)
		{
			return ( (void *)a.get() == (void *)b.get() );
		}
		template<class T, class U> inline bool operator!=(miniutil::data::ref_ptr<T> const & a, miniutil::data::ref_ptr<U> const & b)
		{
			return ( (void *)a.get() != (void *)b.get() );
		}

		template<class T> inline bool operator==(miniutil::data::ref_ptr<T>  & a,  void * p)
		{
			return ( (void *)a.get() == p );
		}
		template<class T> inline bool operator==(  void * p, miniutil::data::ref_ptr<T>  & a)
		{
			return ( (void *)a.get() == p );
		}
		template<class T> inline bool operator!=(miniutil::data::ref_ptr<T>  & a,  void * p)
		{
			return ( (void *)a.get() != p );
		}
		template<class T> inline bool operator!=(  void * p, miniutil::data::ref_ptr<T>  & a)
		{
			return ( (void *)a.get() != p );
		}

		template<class T, class U> inline bool operator<(miniutil::data::ref_ptr<T> const & a, miniutil::data::ref_ptr<U> const & b)
		{
			return ( (void *)a.get() < (void *)b.get() );
		}

	// end namespace miniutil::data
	}
}


#endif
